﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Mono.Diagnostics.Switches;

namespace Monoxide.Diagnostics.Extensions
{
    public class SourceBase
    {
        //Todo-- update to a list of switches.
        GenericSwitch source_switch;
        private TraceListenerCollection listeners;
        private List<Switch> switches = new List<Switch>();
        private string sourceName;

        public SourceBase(string name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            sourceName = name;
            Hashtable sources = DiagnosticsConfiguration.Settings["sources"] as Hashtable;
            TraceSourceInfo info = sources != null ? sources[name] as TraceSourceInfo : null;
            source_switch = new GenericSwitch(name);

            if (info == null)
                listeners = new TraceListenerCollection();
            else
            {
                source_switch.Criteria = info.Levels;
                listeners = info.Listeners;
            }
        }

        //public StringDictionary Attributes {
        //    get { return source_switch.Attributes; }
        //}

        public TraceListenerCollection Listeners
        {
            get { return listeners; }
        }

        public string Name
        {
            get { return sourceName; }
        }

        //First switch
        public Switch Switch
        {
            get { return switches[0]; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("value");
                switches[0] = value;
            }
        }

        public List<Switch> Switches
        {
            get { return switches; }
        }

        public void Close()
        {
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.Close();
            }
        }

        public void Flush()
        {
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.Flush();
            }
        }

        [Conditional("TRACE")]
        public void TraceData(
            TraceEventType eventType, int id, object data)
        {
            if (!source_switch.ShouldTrace(eventType))
                return;
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.TraceData(new TraceEventCache(), Name, eventType, id, data);
            }
        }

        [Conditional("TRACE")]
        public void TraceData(
            TraceEventType eventType, int id, params object[] data)
        {
            if (!source_switch.ShouldTrace(eventType))
                return;
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.TraceData(new TraceEventCache(), Name, eventType, id, data);
            }
        }

        [Conditional("TRACE")]
        public void TraceEvent(TraceEventType eventType, int id)
        {
            if (!source_switch.ShouldTrace(eventType))
                return;
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.TraceEvent(new TraceEventCache(), Name, eventType, id);
            }
        }

        [Conditional("TRACE")]
        public void TraceEvent(TraceEventType eventType,
                               int id, string message)
        {
            if (!source_switch.ShouldTrace(eventType))
                return;
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.TraceEvent(new TraceEventCache(), Name, eventType, id, message);
            }
        }

        [Conditional("TRACE")]
        public void TraceEvent(TraceEventType eventType,
                               int id, string format, params object[] args)
        {
            if (!source_switch.ShouldTrace(eventType))
                return;
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.TraceEvent(new TraceEventCache(), Name, eventType, id, format, args);
            }
        }

        [Conditional("TRACE")]
        public void TraceInformation(string format)
        {
            TraceEvent(TraceEventType.Information, 0, format);
        }

        [Conditional("TRACE")]
        public void TraceInformation(
            string format, params object[] args)
        {
            TraceEvent(TraceEventType.Information, 0, format, args);
        }

        [Conditional("TRACE")]
        public void TraceTransfer(int id, string message, Guid relatedActivityId)
        {
            if (!source_switch.ShouldTrace(TraceEventType.Transfer))
                return;
            lock (((ICollection) listeners).SyncRoot)
            {
                foreach (TraceListener tl in listeners)
                    tl.TraceTransfer(new TraceEventCache(), Name, id, message, relatedActivityId);
            }
        }

        protected virtual string[] GetSupportedAttributes()
        {
            return null;
        }
    }
}